package com.cuile.littletools

import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import com.google.zxing.*
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.qrcode.QRCodeReader
import com.google.zxing.qrcode.QRCodeWriter
import java.util.*
import java.util.regex.Pattern

fun String.isHttpUrl(): Boolean{
    //设置正则表达式
    val regex = "(((https|http)?://)?([a-z0-9]+[.])|(www.))\\w+[.|\\/]([a-z0-9]{0,})?[[.]([a-z0-9]{0,})]+((/[\\S&&[^,;\u4E00-\u9FA5]]+)+)?([.][a-z0-9]{0,}+|/?)"
    return Pattern.compile(regex.trim()).matcher(this.trim()).matches()
}

/**
 * Created by cuile on 18-10-26.
 *
 */
/**
 * 创建二维码位图
 *
 * @param size 位图尺寸(单位:px)
 * @return
 */
fun String.createQRCodeBitmap (size: Int): Bitmap? {
    return this.createQRCodeBitmap(size, "UTF-8", "H", "2", Color.BLACK, Color.WHITE, null, null, 0F)
}


/**
 * 创建二维码位图 (自定义黑、白色块颜色)
 *
 * @param size 位图尺寸
 * @param color_black 黑色色块的自定义颜色值
 * @param color_white 白色色块的自定义颜色值
 * @return
 */
fun String.createQRCodeBitmap (size: Int, color_black: Int, color_white: Int): Bitmap? {
    return this.createQRCodeBitmap(size, "UTF-8", "H", "2", color_black, color_white, null, null, 0F)
}

/**
 * 创建二维码位图 (带Logo小图片)
 *
 * @param size 位图宽&高(单位:px)
 * @param logoBitmap logo图片
 * @param logoPercent logo小图片在二维码图片中的占比大小,范围[0F,1F]。超出范围->默认使用0.2F
 * @return
 */
fun String.createQRCodeBitmap (size: Int, logoBitmap: Bitmap?, logoPercent: Float): Bitmap? {
    return this.createQRCodeBitmap(size, "UTF-8", "H", "2", Color.BLACK, Color.WHITE, null, logoBitmap, logoPercent)
}

/**
 * 创建二维码位图 (Bitmap颜色代替黑色) 注意!!!注意!!!注意!!! 选用的Bitmap图片一定不能有白色色块,否则会识别不出来!!!
 *
 * @param content 字符串内容
 * @param size 位图宽&高(单位:px)
 * @param targetBitmap 目标图片 (如果targetBitmap != null, 黑色色块将会被该图片像素色值替代)
 * @return
 */
fun String.createQRCodeBitmap (size: Int, targetBitmap: Bitmap?): Bitmap? {
    return this.createQRCodeBitmap(size, "UTF-8", "H", "2", Color.BLACK, Color.WHITE, targetBitmap, null, 0F)
}

/**
 * 创建二维码位图 (支持自定义配置和自定义样式)
 * @param size 位图宽&高(单位:px)
 * @param character_set 字符集/字符转码格式 (支持格式:{@link CharacterSetECI })。传null时,zxing源码默认使用 "ISO-8859-1"
 * @param error_correction 容错级别 (支持级别:{@link ErrorCorrectionLevel })。传null时,zxing源码默认使用 "L"
 * @param margin 空白边距 (可修改,要求:整型且>=0), 传null时,zxing源码默认使用"4"。
 * @param color_black 黑色色块的自定义颜色值
 * @param color_white 白色色块的自定义颜色值
 * @param targetBitmap 目标图片 (如果targetBitmap != null, 黑色色块将会被该图片像素色值替代)
 * @param logoBitmap logo小图片
 * @param logoPercent logo小图片在二维码图片中的占比大小,范围[0F,1F],超出范围->默认使用0.2F。
 * @return
 *
 */
fun String.createQRCodeBitmap (size: Int,
                               character_set: String,
                               error_correction: String,
                               margin: String,
                               color_black: Int, color_white: Int,
                               targetBitmap: Bitmap?,
                               logoBitmap: Bitmap?, logoPercent: Float): Bitmap? {
    if (size <= 0) return null


    try {
        // 设置配置参数 生成BitMatrix(位矩阵)对象
        val hints: Hashtable<EncodeHintType, String> = Hashtable()
        hints[EncodeHintType.CHARACTER_SET] = character_set
        hints[EncodeHintType.ERROR_CORRECTION] = error_correction
        hints[EncodeHintType.MARGIN] = margin
        val bitMatrix = QRCodeWriter().encode(this, BarcodeFormat.QR_CODE, size, size, hints)

        // 根据BitMatrix(位矩阵)对象为数组元素赋颜色值
        var backgroundBitmap: Bitmap? = null
        if (targetBitmap != null) {
            backgroundBitmap = Bitmap.createScaledBitmap(targetBitmap, size, size, false)
        }
        val pixels = IntArray(size * size)
        for (y in 0 until size) {
            for (x in 0 until size) {
                if (bitMatrix.get(x, y)) {
                    pixels[y * size + x] = backgroundBitmap?.getPixel(x, y) ?: color_black
                } else {
                    pixels[y * size + x] = color_white
                }
            }
        }

        // 创建Bitmap对象,根据像素数组设置Bitmap每个像素点的颜色值,之后返回Bitmap对象
        val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
        bitmap.setPixels(pixels, 0, size, 0, 0, size, size)

        if (logoBitmap != null) {
            return addLogo(bitmap, logoBitmap, logoPercent)
        }

        return bitmap

    } catch (e: WriterException) {
        e.printStackTrace()
    }

    return null
}

/**
 * 向一张图片中间添加logo小图片(图片合成)
 *
 * @param srcBitmap 原图片
 * @param logoBitmap logo图片
 * @param logoPercent 百分比 (用于调整logo图片在原图片中的显示大小, 取值范围[0,1], 传值不合法时使用0.2F)
 *                    原图片是二维码时,建议使用0.2F,百分比过大可能导致二维码扫描失败。
 * @return
 */
fun addLogo(bitmap: Bitmap, logoBitmap: Bitmap, logoPercent: Float): Bitmap? {
    var percent = logoPercent
    if (logoPercent < 0F || logoPercent > 1F) percent = 0.2F

    val srcWidth = bitmap.width
    val srcHeight = bitmap.height
    val logoWidth = logoBitmap.width
    val logoHeight = logoBitmap.height

    val scaleWidth = srcWidth * logoPercent / logoWidth
    val scaleHeight = srcHeight * logoPercent / logoHeight

    val resultBitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(resultBitmap)
    canvas.drawBitmap(bitmap, 0F, 0F, null)
    canvas.scale(scaleWidth, scaleHeight, srcWidth.toFloat() / 2, srcHeight.toFloat() / 2)
    canvas.drawBitmap(logoBitmap,
            srcWidth.toFloat() / 2 - logoWidth.toFloat() / 2,
            srcHeight.toFloat() / 2 - logoHeight.toFloat() / 2, null)

    return resultBitmap
}

fun Bitmap.getBitmapYUVBytes(): ByteArray {
    val inputWidth = this.width
    val inputHeight = this.height
    val argb = IntArray(inputWidth * inputHeight)
    this.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight)

    var yuv = ByteArray(inputWidth * inputHeight
            + (if (inputWidth % 2 == 0) inputWidth else inputWidth + 1) * (if (inputHeight % 2 == 0) inputHeight else inputHeight + 1) / 2)


    yuv = encodeYUV420SP(yuv, argb, inputWidth, inputHeight)
    this.recycle()
    return yuv
}

/**
 * 将bitmap里得到的argb数据转成yuv420sp格式
 * 这个yuv420sp数据就可以直接传给MediaCodec, 通过AvcEncoder间接进行编码
 *
 * @param yuv420sp 用来存放yuv429sp数据
 * @param argb     传入argb数据
 * @param width    bmpWidth
 * @param height   bmpHeight
 */
private fun encodeYUV420SP(yuv: ByteArray, argb: IntArray, width: Int, height: Int): ByteArray {
    // 帧图片的像素大小
    val frameSize = width * height
    // Y的index从0开始
    var yIndex = 0
    // UV的index从frameSize开始
    var uvIndex = frameSize
    // YUV数据, ARGB数据
    var Y: Int
    var U: Int
    var V: Int
    var a: Int
    var R: Int
    var G: Int
    var B: Int

    var argbIndex = 0;
    // ---循环所有像素点，RGB转YUV---
    for (j in 0 until height) {
        for (i in 0 until width) {

            // a is not used obviously
            a = (argb[argbIndex] and 0xff000000.toInt()) shr 24
            R = (argb[argbIndex] and 0xff0000) shr 16
            G = (argb[argbIndex] and 0xff00) shr 8
            B = (argb[argbIndex] and 0xff)
            argbIndex++;

            // well known RGB to YUV algorithm
            Y = ((66 * R + 129 * G + 25 * B + 128) shr 8) + 16
            U = ((-38 * R - 74 * G + 112 * B + 128) shr 8) + 128
            V = ((112 * R - 94 * G - 18 * B + 128) shr 8) + 128

            Y = Math.max(0, Math.min(Y, 255))
            U = Math.max(0, Math.min(U, 255))
            V = Math.max(0, Math.min(V, 255))

            // NV21 has a plane of Y and interleaved planes of VU each
            // sampled by a factor of 2
            // meaning for every 4 Y pixels there are 1 V and 1 U. Note the
            // sampling is every other
            // pixel AND every other scanline.
            // ---Y---
            yuv[yIndex++] = Y.toByte()
            // ---UV---
            if ((j % 2 == 0) && (i % 2 == 0)) {
                yuv[uvIndex++] = V.toByte()
                yuv[uvIndex++] = U.toByte()
            }
        }
    }

    return yuv
}

fun ByteArray.decodeYUVByZxing(width: Int, height: Int): String? {

    val source = PlanarYUVLuminanceSource(this, width, height, 0, 0, width, height, true)
    val binaryBitmap = BinaryBitmap(HybridBinarizer(source))
    return try {
        QRCodeReader().decode(binaryBitmap)?.text
    } catch (e: Exception) {
        null
    }
}

fun Bitmap.getSmallerBitmap(): Bitmap {
    val size = width * height / 160000
    return if (size <= 1) {
        this
    } else {
        val matrix = Matrix().apply{ postScale((1 / Math.sqrt(size.toDouble())).toFloat(), (1 / Math.sqrt(size.toDouble())).toFloat())}
        Bitmap.createBitmap(this, 0, 0, width, height, matrix, true)
    }
}